package com.migration.service.impl;

import com.migration.generator.ModelGenerator;
import com.migration.service.MigrationService;
import com.migration.util.MigrationUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Duration;
import java.time.Instant;
import java.util.*;

/**
 * 数据迁移服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MigrationServiceImpl implements MigrationService {

    @Qualifier("oldDataSource")
    private final DataSource oldDataSource;

    @Qualifier("newDataSource")
    private final DataSource newDataSource;

    private final ModelGenerator modelGenerator;
    private final MigrationUtils migrationUtils;

    /**
     * 获取数据库所有表
     */
    @Override
    public List<String> getAllTables(List<String> excludePrefixes) {
        return migrationUtils.getTableList(oldDataSource, excludePrefixes);
    }

    /**
     * 获取表结构信息
     */
    @Override
    public Map<String, Object> getTableStructure(String tableName) {
        Map<String, Object> result = new HashMap<>();
        
        try (Connection conn = oldDataSource.getConnection()) {
            DatabaseMetaData metaData = conn.getMetaData();
            String catalog = conn.getCatalog();
            String schema = conn.getSchema();
            
            // 获取列信息
            List<Map<String, Object>> columns = new ArrayList<>();
            try (ResultSet rs = metaData.getColumns(catalog, schema, tableName, "%")) {
                while (rs.next()) {
                    Map<String, Object> column = new HashMap<>();
                    column.put("name", rs.getString("COLUMN_NAME"));
                    column.put("type", rs.getString("TYPE_NAME"));
                    column.put("size", rs.getInt("COLUMN_SIZE"));
                    column.put("nullable", rs.getInt("NULLABLE") == DatabaseMetaData.columnNullable);
                    column.put("defaultValue", rs.getString("COLUMN_DEF"));
                    column.put("remarks", rs.getString("REMARKS"));
                    columns.add(column);
                }
            }
            result.put("columns", columns);
            
            // 获取主键信息
            List<String> primaryKeys = new ArrayList<>();
            try (ResultSet rs = metaData.getPrimaryKeys(catalog, schema, tableName)) {
                while (rs.next()) {
                    primaryKeys.add(rs.getString("COLUMN_NAME"));
                }
            }
            result.put("primaryKeys", primaryKeys);
            
            // 获取外键信息
            List<Map<String, Object>> foreignKeys = new ArrayList<>();
            try (ResultSet rs = metaData.getImportedKeys(catalog, schema, tableName)) {
                while (rs.next()) {
                    Map<String, Object> foreignKey = new HashMap<>();
                    foreignKey.put("fkColumnName", rs.getString("FKCOLUMN_NAME"));
                    foreignKey.put("pkTableName", rs.getString("PKTABLE_NAME"));
                    foreignKey.put("pkColumnName", rs.getString("PKCOLUMN_NAME"));
                    foreignKeys.add(foreignKey);
                }
            }
            result.put("foreignKeys", foreignKeys);
            
            // 获取索引信息
            List<Map<String, Object>> indexes = new ArrayList<>();
            try (ResultSet rs = metaData.getIndexInfo(catalog, schema, tableName, false, false)) {
                while (rs.next()) {
                    Map<String, Object> index = new HashMap<>();
                    index.put("indexName", rs.getString("INDEX_NAME"));
                    index.put("columnName", rs.getString("COLUMN_NAME"));
                    index.put("nonUnique", rs.getBoolean("NON_UNIQUE"));
                    indexes.add(index);
                }
            }
            result.put("indexes", indexes);
            
            // 获取表的记录数
            long rowCount = migrationUtils.getTableRowCount(migrationUtils.getOldJdbcTemplate(), tableName);
            result.put("rowCount", rowCount);
            
            return result;
        } catch (SQLException e) {
            log.error("获取表 {} 结构信息失败", tableName, e);
            throw new RuntimeException("获取表结构信息失败: " + e.getMessage(), e);
        }
    }

    /**
     * 迁移单个表
     */
    @Override
    @Transactional
    public Map<String, Object> migrateSingleTable(String tableName) {
        Map<String, Object> result = new HashMap<>();
        Instant start = Instant.now();
        
        try {
            int rowsMigrated = migrationUtils.migrateSingleTable(tableName);
            Instant end = Instant.now();
            Duration duration = Duration.between(start, end);
            
            result.put("success", true);
            result.put("tableName", tableName);
            result.put("rowsMigrated", rowsMigrated);
            result.put("durationMs", duration.toMillis());
            result.put("message", "成功迁移 " + rowsMigrated + " 条记录");
            
            return result;
        } catch (Exception e) {
            log.error("迁移表 {} 失败", tableName, e);
            
            result.put("success", false);
            result.put("tableName", tableName);
            result.put("error", e.getMessage());
            result.put("durationMs", Duration.between(start, Instant.now()).toMillis());
            
            return result;
        }
    }

    /**
     * 迁移所有表
     */
    @Override
    @Transactional
    public Map<String, Object> migrateAllTables(List<String> excludePrefixes) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> tableResults = new ArrayList<>();
        Instant start = Instant.now();
        
        List<String> tables = getAllTables(excludePrefixes);
        int successCount = 0;
        int failCount = 0;
        long totalRows = 0;
        
        for (String tableName : tables) {
            Map<String, Object> tableResult = migrateSingleTable(tableName);
            tableResults.add(tableResult);
            
            if ((Boolean) tableResult.get("success")) {
                successCount++;
                totalRows += (Integer) tableResult.get("rowsMigrated");
            } else {
                failCount++;
            }
        }
        
        Instant end = Instant.now();
        Duration duration = Duration.between(start, end);
        
        result.put("success", failCount == 0);
        result.put("totalTables", tables.size());
        result.put("successTables", successCount);
        result.put("failedTables", failCount);
        result.put("totalRows", totalRows);
        result.put("durationMs", duration.toMillis());
        result.put("details", tableResults);
        
        return result;
    }
} 